/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ke.me.muhia.spring.masomo.provisioning.ucip;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import ke.me.muhia.spring.masomo.provisioning.xmlrpc.CustomTypeFactory;
import ke.me.muhia.spring.masomo.provisioning.xmlrpc.CustomXmlRpcSunTransportFactory;
import ke.me.muhia.spring.masomo.provisioning.xmlrpc.MessageLoggingTransport;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcClientRequestImpl;
import org.apache.xmlrpc.client.XmlRpcSunHttpTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Kenneth
 */
public class CustomMethods {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    MessageLoggingTransport http;
//    XmlRpcClientConfigImpl config = null;

    /**
     * Create and confgure the XML-RPC Client
     *
     * @param config
     * @return
     */
    public XmlRpcClient createXmlRpcClient(XmlRpcClientConfigImpl config) {
        XmlRpcClient client = new XmlRpcClient();

        // XmlRpcSunHttpTransport http = new XmlRpcSunHttpTransport(client);
        client.setTypeFactory(new CustomTypeFactory(client));
        client.setConfig(config);
        client.setTransportFactory(new CustomXmlRpcSunTransportFactory(client));
        return client;
    }

    /**
     *
     * @param params
     * @return
     */
    public XmlRpcClientConfigImpl createXmlRpcConfig(UCIPParameters params) {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        try {
            config = new XmlRpcClientConfigImpl();
            config.setServerURL(new URL(params.getStrURL()));
            config.setEnabledForExceptions(true);
            config.setBasicUserName(params.getuName());
            config.setBasicPassword(params.getuPass());
            config.setEncoding(XmlRpcClientConfigImpl.UTF8_ENCODING);
            config.setReplyTimeout(params.getReplyTimeout());
            config.setUserAgent(params.getUserAgent());
            config.setConnectionTimeout(params.getConnectTimeout());
            config.setContentLengthOptional(true);

        } catch (MalformedURLException ex) {
            logger.error(ex.getMessage(), ex);
        }
        return config;
    }

    /**
     * Create the XML-RPC Transport
     *
     * @param client
     * @return
     */
    public XmlRpcSunHttpTransport createTransport(XmlRpcClient client) {
        if (http == null) {
            http = new MessageLoggingTransport(client);
        }
        return http;
    }

    /**
     *
     * @param xml
     * @return
     */
    public Hashtable returnElements(String xml) {
        Hashtable<String, String> htElements = new Hashtable();
        try {
            // Create a factory
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            // Use the factory to create a builder
            DocumentBuilder builder = factory.newDocumentBuilder();

            // Get the xml document
            Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));

            // Get a list of all elements in the document assuming it has a struct object
            NodeList list = doc.getElementsByTagName("struct");
            Element elements = (Element) list.item(0);
            NodeList items = elements.getChildNodes();
            for (int i = 0; i < items.getLength(); i++) {
                Element element = (Element) items.item(i);
                NodeList item = element.getChildNodes();
                NodeList value = item.item(1).getChildNodes();
                if (value.item(0).getChildNodes().item(0).getNodeName().equals("array")) {
                    /**
                     * TODO: Figure out how to deal with Arrays, now in testing
                     */
//                    NodeList lista = doc.getElementsByTagName("array");
//                    
//                    Element elementsa = (Element) lista.item(0);
//                    NodeList itemsa = elementsa.getChildNodes();
//                    Hashtable<String, Object>[] htArrays;
////                    htArrays = new Hashtable<String, Object>[itemsa.getLength()];
//                    for (int j = 0; j < itemsa.getLength(); j++) {
//                        Element arrayElement = (Element) items.item(j);
//                        NodeList arrayItem = arrayElement.getChildNodes();
//                        NodeList arrayValue = arrayItem.item(1).getChildNodes();
//                        htElements.put(itemsa.item(0).getTextContent(), arrayValue.item(0).getTextContent());
//                        
//                    }

                }
                htElements.put(item.item(0).getTextContent(), value.item(0).getTextContent());

            }
        } catch (ParserConfigurationException | SAXException | IOException ex) {
            logger.error(ex.getMessage(), ex);
        }
        return htElements;
    }

    /**
     *
     * @param config
     * @param transport
     * @param methodvector
     * @param methodName
     * @return
     */
    public HashMap xmlRpcMethodExecutor(XmlRpcClientConfigImpl config, XmlRpcSunHttpTransport transport, Vector methodvector, String methodName) {
//        Hashtable<String, Object> htElements = new Hashtable<>();
        HashMap xmlout = new HashMap();

        try {

            xmlout = (HashMap) transport.sendRequest(new XmlRpcClientRequestImpl(config, methodName, methodvector));

//            htElements = returnElements(xmlout);
        } catch (XmlRpcException | StackOverflowError ex) {
            logger.error(ex.getMessage(), ex);
        }
        return xmlout;
    }

    /**
     *
     * @param client
     * @param methodvector
     * @param methodName
     * @return
     */
    public Hashtable xmlRpcMethodExecutor(XmlRpcClient client, Vector methodvector, String methodName) {
        Hashtable<String, Object> htElements = new Hashtable<>();

        try {
            String xmlout = (String) client.execute(methodName, methodvector);

            htElements = returnElements(xmlout);

        } catch (XmlRpcException ex) {
            logger.error(ex.getMessage(), ex);
        }
        return htElements;
    }

    /**
     * Used to Create the HashMap for the GetBalanceAndDate method call
     *
     * @param tsubscriberNumberNAI
     * @param tOriginNodeType
     * @param tOriginHostName
     * @param tOriginTransactionID
     * @param tOriginTimeStamp
     * @param tSubscriberNumber
     * @return
     */
    public Vector createGetBalanceandDateHash(int tsubscriberNumberNAI, String tOriginNodeType, String tOriginHostName, String tOriginTransactionID, Date tOriginTimeStamp, String tSubscriberNumber) {
        Vector v = new Vector();

        Hashtable request = new Hashtable();
        request.put("originNodeType", tOriginNodeType);
        request.put("originHostName", tOriginHostName);
        request.put("originTransactionID", tOriginTransactionID);
        request.put("originTimeStamp", tOriginTimeStamp);
        request.put("subscriberNumberNAI", tsubscriberNumberNAI);
        request.put("subscriberNumber", tSubscriberNumber);

        v.add(request);

        return v;
    }

    /**
     * UCIP 4.3 GetBalanceAndDateResponse
     *
     * @param methodResp
     * @return
     */
    public HashMap getBalanceAndDateResp(HashMap methodResp) {
        HashMap<String, String> balHashMap = new HashMap<>();
        try {
            for (Map.Entry entry : balHashMap.entrySet()) {
                if (entry.getKey().equals("dedicatedAccountInformation")) {

                    Object[] objects = (Object[]) entry.getValue();

                    for (Object object : objects) {
                        HashMap hashMap = (HashMap) object;
                        Iterator iterArr = hashMap.entrySet().iterator();
                        String key = "", val = "";

                        while (iterArr.hasNext()) {

                            Map.Entry entryArrs = (Map.Entry) iterArr.next();

//                            balHashMap.put(entryArrs.getKey().toString(), entryArrs.getValue().toString());
                            if (entryArrs.getKey().equals("dedicatedAccountID")) {
                                key = entryArrs.getKey().toString() + entryArrs.getValue().toString();

                            } else {
                                val = val + entryArrs.getKey().toString() + ":" + entryArrs.getValue().toString() + " ";
                                logger.debug(entryArrs.getKey() + ":" + entryArrs.getValue());
                            }

                        }
                        balHashMap.put(key, val);

//			System.out.printf("dedicatedAccountInformation \"%s\"%n",objects[i]);
//                        logger.info("dedicatedAccountInformation" + object);
                    }

                } else if (entry.getKey().equals("responseCode")) {
                    /**
                     * TODO: Get Response Code descriptions from Persisted...
                     */
                    balHashMap.put(entry.getKey().toString(), entry.getValue().toString());
                    logger.debug("Request response code is :" + entry.getValue());
                } else {
                    balHashMap.put(entry.getKey().toString(), entry.getValue().toString());
                    logger.debug(entry.getKey() + ":" + entry.getValue());
                }
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        return balHashMap;
    }

    /**
     * UCIP 4.3 Generic MethodResponse
     *
     * @param methodResp
     * @return
     */
    public HashMap MethodResponse(HashMap methodResp) {
        HashMap<String, String> balHashMap = new HashMap<>();
        try {
            for (Map.Entry entry : balHashMap.entrySet()) {
                if (entry.getKey().equals("responseCode")) {
                    /**
                     * TODO: Get Response Code descriptions from Persisted...
                     */
                    balHashMap.put(entry.getKey().toString(), entry.getValue().toString());
                    logger.debug("Request response code is :" + entry.getValue());
                } else {
                    balHashMap.put(entry.getKey().toString(), entry.getValue().toString());
                    logger.debug(entry.getKey() + ":" + entry.getValue());
                }
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        return balHashMap;
    }

    /**
     * UCIP 4.3 Update Service class Method
     *
     * @param tsubscriberNumberNAI
     * @param tOriginNodeType
     * @param tOriginHostName
     * @param tOriginTransactionID
     * @param tOriginTimeStamp
     * @param tSubscriberNumber
     * @param tServiceClassNew
     * @param tServiceClassAction
     * @return
     */
    public Vector UpdateServiceClassHash(int tsubscriberNumberNAI, String tOriginNodeType, String tOriginHostName, String tOriginTransactionID, Date tOriginTimeStamp, String tSubscriberNumber, int tServiceClassNew, String tServiceClassAction) {
        Vector v = new Vector();

        Hashtable request = new Hashtable();
        request.put("originNodeType", tOriginNodeType);
        request.put("originHostName", tOriginHostName);
        request.put("originTransactionID", tOriginTransactionID);
        request.put("originTimeStamp", tOriginTimeStamp);
        request.put("subscriberNumberNAI", tsubscriberNumberNAI);
        request.put("subscriberNumber", tSubscriberNumber);
        request.put("serviceClassNew", tServiceClassNew);
        request.put("serviceClassAction", tServiceClassAction);

        v.add(request);

        return v;
    }

    public Vector RefillHash(int tsubscriberNumberNAI, String tOriginNodeType, String tOriginHostName, String tOriginTransactionID, Date tOriginTimeStamp, String tSubscriberNumber, String tTransactionCurrency, String tRefillProfileID, String tTransactionAmount) {
        Vector v = new Vector();

        Hashtable request = new Hashtable();
        request.put("originNodeType", tOriginNodeType);
        request.put("originHostName", tOriginHostName);
        request.put("originTransactionID", tOriginTransactionID);
        request.put("originTimeStamp", tOriginTimeStamp);
        request.put("subscriberNumberNAI", tsubscriberNumberNAI);
        request.put("subscriberNumber", tSubscriberNumber);
        request.put("transactionCurrency", tTransactionCurrency);
        request.put("refillProfileID", tRefillProfileID);
        request.put("transactionAmount", tTransactionAmount);

        v.add(request);

        return v;
    }

}
